from fastapi import FastAPI, HTTPException, Depends, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
import bcrypt
from models import DiabetesPatient, Gender, DiabetesType, SmokingStatus, DrinkingStatus

app = FastAPI(title="用户管理API")

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173","http://127.0.0.1:5173"],  # 开发环境允许所有源，生产环境应限制
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],  # 显式添加OPTIONS方法
    allow_headers=["*"],
)
# 数据库配置
SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:1234@127.0.0.1/tangliaobing?charset=utf8mb4"
engine = create_engine(
    SQLALCHEMY_DATABASE_URL,
    pool_pre_ping=True,
    pool_recycle=3600,
    pool_size=5,
    max_overflow=10
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()


# SQLAlchemy 数据模型
class DBUser(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    username = Column(String(50), unique=True, index=True)
    password = Column(String(255))  # 增加密码字段长度以存储bcrypt哈希值


# 创建数据库表
Base.metadata.create_all(bind=engine)




# 数据库依赖
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


# Pydantic 模型 - 输入验证
class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50, example="john_doe")
    password: str = Field(..., min_length=3, example="strong_password")


# Pydantic 模型 - 响应模型（隐藏密码）
class User(BaseModel):
    id: int
    username: str

    class Config:
        from_attributes = True


# Pydantic 模型 - 登录响应
class LoginResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    user: User


# Pydantic 模型 - 患者创建/更新
class PatientCreate(BaseModel):
    id:int=Field(..., gt=0,lt=9999)
    name: str = Field(..., min_length=1, max_length=50)
    gender: Gender
    age: int = Field(..., gt=0, lt=120)
    contact: str = Field(..., min_length=5, max_length=20)
    id_card: str = Field(..., min_length=15, max_length=18)
    address: str = Field(..., min_length=1, max_length=200)
    diagnosis_date: date
    diabetes_type: DiabetesType
    diet: str | None = None
    smoking_status: SmokingStatus | None = None
    drinking_status: DrinkingStatus | None = None


# Pydantic 模型 - 患者响应
class Patient(BaseModel):
    id: int
    name: str
    gender: Gender
    age: int
    contact: str
    id_card: str
    address: str
    diagnosis_date: date
    diabetes_type: DiabetesType
    diet: str | None
    smoking_status: SmokingStatus | None
    drinking_status: DrinkingStatus | None

    class Config:
        from_attributes = True


# 根路由
@app.get("/", status_code=status.HTTP_200_OK)
async def root():
    return {"message": "用户管理API服务运行中"}


# 创建用户
@app.post("/users/", response_model=User, status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate, db: Session = Depends(get_db)):
    # 检查用户名是否已存在
    db_user = db.query(DBUser).filter(DBUser.username == user.username).first()
    if db_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户名已存在"
        )

    # 哈希密码
    hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())

    # 创建数据库用户
    db_user = DBUser(
        username=user.username,
        password=hashed_password
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)

    return db_user  # 自动转换为User模型，隐藏密码字段


# 用户登录
@app.post("/login", response_model=LoginResponse)
async def login(user: UserCreate, db: Session = Depends(get_db)):
    # 检查用户名是否存在
    db_user = db.query(DBUser).filter(DBUser.username == user.username).first()
    if not db_user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误"
        )

    # 验证密码
    if not bcrypt.checkpw(user.password.encode('utf-8'), db_user.password.encode('utf-8')):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误"
        )

    # 这里简单返回用户信息，实际应用中应该生成JWT token
    return {
        "access_token": "example_token",  # 实际应用中替换为真实token
        "token_type": "bearer",
        "user": db_user
    }


# 获取单个用户
@app.get("/users/{user_id}", response_model=User, status_code=status.HTTP_200_OK)
async def read_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(DBUser).filter(DBUser.id == user_id).first()
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户不存在"
        )
    return user


# 获取所有用户
@app.get("/users/", response_model=list[User], status_code=status.HTTP_200_OK)
async def read_all_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = db.query(DBUser).offset(skip).limit(limit).all()
    return users


# 检查用户名是否可用
@app.get("/users/check/{username}", status_code=status.HTTP_200_OK)
async def check_username_available(username: str, db: Session = Depends(get_db)):
    db_user = db.query(DBUser).filter(DBUser.username == username).first()
    return {"available": db_user is None}


# 示例路由
@app.get("/hello/{name}", status_code=status.HTTP_200_OK)
async def say_hello(name: str):
    return {"message": f"你好阿，{name}！欢迎使用API"}


# 创建患者
@app.post("/patients/", response_model=Patient, status_code=status.HTTP_201_CREATED)
async def create_patient(patient: PatientCreate, db: Session = Depends(get_db)):
    # 检查身份证号是否已存在
    db_patient = db.query(DiabetesPatient).filter(DiabetesPatient.id_card == patient.id_card).first()
    if db_patient:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="身份证号已存在"
        )

    db_patient = DiabetesPatient(**patient.model_dump())
    db.add(db_patient)
    db.commit()
    db.refresh(db_patient)
    return db_patient


# 获取所有患者


@app.get("/patients/", response_model=list[Patient], status_code=status.HTTP_200_OK)
async def read_all_patients(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    patients = db.query(DiabetesPatient).offset(skip).limit(limit).all()
    return patients


# 获取单个患者
@app.get("/patients/{patient_id}", response_model=Patient, status_code=status.HTTP_200_OK)
async def read_patient(patient_id: int, db: Session = Depends(get_db)):
    patient = db.query(DiabetesPatient).filter(DiabetesPatient.patients_id == patient_id).first()
    if not patient:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="患者不存在"
        )
    return patient


# 更新患者
@app.put("/patients/{patient_id}", response_model=Patient, status_code=status.HTTP_200_OK)
async def update_patient(patient_id: int, patient: PatientCreate, db: Session = Depends(get_db)):
    db_patient = db.query(DiabetesPatient).filter(DiabetesPatient.patients_id == patient_id).first()
    if not db_patient:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="患者不存在"
        )

    # 检查身份证号是否被其他患者使用
    if patient.id_card != db_patient.id_card:
        existing_patient = db.query(DiabetesPatient).filter(
            DiabetesPatient.id_card == patient.id_card,
            DiabetesPatient.patients_id != patient_id
        ).first()
        if existing_patient:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="身份证号已被其他患者使用"
            )

    for key, value in patient.model_dump().items():
        setattr(db_patient, key, value)

    db.commit()
    db.refresh(db_patient)
    return db_patient


# 删除患者
@app.delete("/patients/{patient_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_patient(patient_id: int, db: Session = Depends(get_db)):
    patient = db.query(DiabetesPatient).filter(DiabetesPatient.patients_id == patient_id).first()
    if not patient:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="患者不存在"
        )

    db.delete(patient)
    db.commit()
    return None
